package br.com.unirio.formula1.modelo.fabrica;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import br.com.unirio.formula1.modelo.ColocacaoResultado;
import br.com.unirio.formula1.modelo.Corrida;
import br.com.unirio.formula1.modelo.Piloto;
import br.com.unirio.formula1.modelo.Resultado;
import br.com.unirio.formula1.util.exception.ExcecaoDeModelo;

/**
 * Classe estatica responsavel por retornar instancias de resultados ({@link Resultado}), aplicando as devidas regras de
 * negocio e verificacoes.
 * 
 * @author Victor
 * 
 */
public class FabricaResultado
{
    static double vetorPontos[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };

    public FabricaResultado()
    {

    }

    public static Resultado criaResultado(Corrida corrida, String voltasRealizadas, HashMap<Integer, Piloto> colocados)
	    throws ExcecaoDeModelo
    {
	Resultado resultado = new Resultado();
	resultado.setCorrida(corrida);

	int voltas = Integer.parseInt(voltasRealizadas);
	verificaVoltas(voltas);
	resultado.setVoltasRealizadas(voltas);

	// gera colocacoes de resultado atraves do mapeamento de posicao-piloto
	ArrayList<ColocacaoResultado> colocadosResultado = gerarColocadosResultado(colocados, voltas,
		corrida.getVoltasPrevistas());

	Collections.sort(colocadosResultado);
	resultado.setColocados(colocadosResultado);

	return resultado;

    }

    private static ArrayList<ColocacaoResultado> gerarColocadosResultado(HashMap<Integer, Piloto> mapDeColocados,
	    int voltasRealizadas, int voltasPrevistas) throws ExcecaoDeModelo
    {
	ArrayList<ColocacaoResultado> colocadosResultado = new ArrayList<ColocacaoResultado>();
	for (Integer posicao : mapDeColocados.keySet())
	{

	    ColocacaoResultado colocacao = new ColocacaoResultado();
	    colocacao.setPosicao(posicao);
	    colocacao.setPiloto(mapDeColocados.get(posicao));
	    colocacao.setPontos(calculaPontosPiloto(posicao, voltasRealizadas, voltasPrevistas));
	    colocadosResultado.add(colocacao);

	}

	return colocadosResultado;
    }

    private static void verificaVoltas(int voltasRealizadas) throws ExcecaoDeModelo
    {
	if (voltasRealizadas < 0)
	    throw new ExcecaoDeModelo("FabricaResultado.voltasRealizadasNegativas");

    }

    /**
     * Metodo que calcula os pontos de um piloto em uma corrida baseado nas regras de negocio.
     * 
     * @param posicaoDoPiloto
     * @param voltasRealizadas
     * @param voltasPrevistas
     * @return
     */
    private static double calculaPontosPiloto(int posicaoDoPiloto, int voltasRealizadas, int voltasPrevistas)
    {

	// 75% do numero de voltas previstas
	double porcentagemDoNumeroDeVoltasPrevistas = 0.75 * voltasPrevistas;

	if (posicaoDoPiloto > 10)
	    return 0;

	if (voltasRealizadas == 1) // pontuacao nula
	{
	    return 0;
	}
	if (voltasRealizadas > 1 && voltasRealizadas < porcentagemDoNumeroDeVoltasPrevistas)
	{
	    return vetorPontos[posicaoDoPiloto - 1] / 2; // pontuacao pela metade
	}
	return vetorPontos[posicaoDoPiloto - 1]; // pontuacao normal

    }

}
